package com.jrmf.redenvelopes.order.controller;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.ParserConfigurationException;

import com.jrmf.redenvelopes.order.dao.AccountThirdXfMapper;
import com.jrmf.redenvelopes.order.dao.DepositdataThirdImportlogMapper;
import com.jrmf.redenvelopes.order.model.AccountThirdXf;
import com.jrmf.redenvelopes.order.model.DepositdataThirdImportlog;
import com.jrmf.redenvelopes.order.util.DateUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.util.SAXHelper;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.taikang.healthcare.sdk.bean.Result;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.multipart.MultipartFile;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

@RestController
@Validated
@RequestMapping("xfDepositDataImportController")
@Api(value = "xfDepositDataImportController", description = "先锋入金数据导入")
public class XfDepositDataImportController {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Resource
	private AccountThirdXfMapper acountThirdXfMapper;
	@Resource
	private DepositdataThirdImportlogMapper depositdataThirdImportlogMapper;
	private String filename;
	private SheetContentsHandler handler;

	public XfDepositDataImportController(){
	}
	public XfDepositDataImportController(String filename){
		this.filename = filename;
	}

	public XfDepositDataImportController setHandler(XSSFSheetXMLHandler.SheetContentsHandler handler) {
		this.handler = handler;
		return this;
	}


	public void parse(){
		OPCPackage pkg = null;
		InputStream sheetInputStream = null;

		try {
			pkg = OPCPackage.open(filename, PackageAccess.READ);
			XSSFReader xssfReader = new XSSFReader(pkg);

			StylesTable styles = xssfReader.getStylesTable();
			ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(pkg);
			sheetInputStream = xssfReader.getSheetsData().next();

			processSheet(styles, strings, sheetInputStream);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage(), e);
		}finally {
			if(sheetInputStream != null){
				try {
					sheetInputStream.close();
				} catch (IOException e) {
					throw new RuntimeException(e.getMessage(), e);
				}
			}
			if(pkg != null){
				try {
					pkg.close();
				} catch (IOException e) {
					throw new RuntimeException(e.getMessage(), e);
				}
			}
		}
	}

	private void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, InputStream sheetInputStream) throws SAXException, ParserConfigurationException, IOException{
		XMLReader sheetParser = SAXHelper.newXMLReader();

		if(handler != null){
			sheetParser.setContentHandler(new XSSFSheetXMLHandler(styles, strings, handler, false));
		}else{
			sheetParser.setContentHandler(new XSSFSheetXMLHandler(styles, strings, new SimpleSheetContentsHandler(), false));
		}

		sheetParser.parse(new InputSource(sheetInputStream));
	}

	public static class SimpleSheetContentsHandler implements SheetContentsHandler{
		protected LinkedList<String> row = new LinkedList<>();
		AccountThirdXf accountThirdXf = new AccountThirdXf();
		int currentRow =0;

		@Override
		public void startRow(int rowNum) {
			currentRow =rowNum;
			row.clear();
			accountThirdXf =new AccountThirdXf();
		}

		@Override
		public void endRow(int rowNum) {
			//logger.info(rowNum + " : " + row);
		}

		@Override
		public void cell(String cellReference, String formattedValue, XSSFComment comment) {
			row.add(formattedValue);
		}

		@Override
		public void headerFooter(String text, boolean isHeader, String tagName) {

		}
	}

    @ApiImplicitParams({
            @ApiImplicitParam(name = "data", value = "对账单日期(格式:20190101)", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "type", value = "第三方支付平台(1:先锋、2:酷宝)", required = true, dataType = "String", paramType = "query"),
    })
    @PostMapping(value = "/depositImport", consumes = "multipart/*", headers = "content-type=multipart/form-data")
    @ResponseBody
    public Result<Object> depositFileUoload(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request, @RequestParam String data, @RequestParam String type){
        Result<Object> resultObj =new Result<>();

        //判断上传文件的格式
        String fileName = multipartFile.getOriginalFilename();
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            resultObj.setCode("0");
            resultObj.setMsg("上传的文件格式不正确");
            return  resultObj;
        }
        String file = saveFile(multipartFile, request,data,type);//存储至本地

        if("0".equals(file)){
            resultObj.setCode("0");
            resultObj.setMsg("已存在该文件，不允许重新导入！");
            return  resultObj;
        }

        File fil =new File(file);
        if(fil.exists() && fil.isFile()){//存储成功
            logger.info("上传至服务器成功！");
            //执行解析存储数据
            filename =file;
            resultObj=depositDataImport(data);

        }
        else {
            resultObj.setCode("0");
            resultObj.setMsg("上传失败！");
        }
        return resultObj;
    }


    //数据文件保存至服务器
    private String saveFile(MultipartFile multipartFile, HttpServletRequest request,String data,String type) {
        String path;
        String fileName = multipartFile.getOriginalFilename();
        // 判断文件类型
        //String realPath = request.getSession().getServletContext().getRealPath("/");
        String dir = "";
        // 设置存放Excel文件的路径
        if ("1".equals(type)){// todo 改为配置文件 服务器地址不一样
            //dir = "C:\\develop\\accountData\\"+"xf\\"+data;
			dir = "/data/account_data/xf/"+data;
        }
        else if ("2".equals(type)){
            //dir = "C:\\develop\\accountData\\"+"kb\\"+data;
			dir = "/data/account_data/kb/"+data;
        }
        else {
            //dir = "C:\\develop\\accountData\\"+"other\\"+data;
			dir = "/data/account_data/other/"+data;
        }
        File di = new File(dir);

        if(!di.exists()){//创建文件夹
            di.mkdirs();
        }
        path =dir+"/"+fileName;
        File tarFile = new File(path);
        if (tarFile.exists() && tarFile.isFile()) {//暂时不允许重复上传
            return "0";
            //tarFile.delete();
        }
        try {
            multipartFile.transferTo(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return path;
    }


	/**
	 * @author  weixiaofeng
	 * @date 	2019/04/25
	 * @return
	 */

	public Result<Object> depositDataImport(String data){
		long start = System.currentTimeMillis();
		Result<Object> resultObj =new Result<>();
		final List<AccountThirdXf> xfList =new ArrayList<>();

		handler =new SimpleSheetContentsHandler(){ //初始化handler


			@Override
			public void endRow(int rowNum) {
				if(rowNum == 0 || rowNum == 1 || rowNum == 2 || rowNum == 3){
					// 第一行中文描述忽略
				}
				else {//从第四行开始解析数据
					if(null!=accountThirdXf.getTradeTime() && !"".equals(accountThirdXf.getTradeTime().toString())){
						accountThirdXf.setDateTime(accountThirdXf.getTradeTime().toString().substring(0,10).replace("-",""));
					}
					accountThirdXf.setThirdpartyPaytype((short) 1);
					xfList.add(accountThirdXf);//结束
				}
			}
			@Override
			public void cell(String cellReference, String formattedValue, XSSFComment comment) {
				String cellCol =cellReference.substring(0,1);
					if(currentRow == 0 || currentRow == 1 || currentRow == 2 || currentRow == 3){
						// 忽略非数据区域
						//logger.info("引用位置："+cellCol);
					}
					else{//解析数据区域
						switch (cellCol) { //判断位置索引 封装对象属性参数
							case "A":
								accountThirdXf.setCertNo(formattedValue);
								break;
							case "B":
								accountThirdXf.setTradeTime(formattedValue);
								break;
							case "C":
								accountThirdXf.setTradeNo(formattedValue);
								break;
							case "E":
								accountThirdXf.setPayIn(Double.valueOf(formattedValue.replace(",","")));
								break;
							case "F":
								accountThirdXf.setPayOut(Double.valueOf(formattedValue.replace(",","")));
								break;
							case "G":
								accountThirdXf.setTotalLeft(Double.valueOf(formattedValue.replace(",","")));
								break;
							case "H":
								accountThirdXf.setAccount(formattedValue);
								break;
							case "I":
								if ("充值".equals(formattedValue)||"转入".equals(formattedValue)) {
									accountThirdXf.setType((short) 1);
								} else if ("转出".equals(formattedValue)) {
									accountThirdXf.setType((short) 2);
								} else {
									accountThirdXf.setType((short) 3);
								}
								break;
							default:
								//logger.info(formattedValue);
								break;
						}
					}
			}
		};
		//filename ="C:\\develop\\先锋结算23号账单.xlsx";//初始化文件信息
		parse();//解析
		long end1 = System.currentTimeMillis();//记录解析数据执行时间
		int totalNum =xfList.size();
		logger.info("一共"+totalNum+"条数据");
		logger.info("解析先锋入金excel文件花费:"+(end1 - start)/1000+"s");

		//分批次导入系统
		int pageSize =0;
		if(totalNum%1024==0){
			pageSize=totalNum/2014;
		}
		else{
			pageSize=(totalNum/1024)+1;
		}
		int successCount =0;
		for(int i=1;i<=pageSize;i++){
			//创建新的
			if(i==pageSize){
				//从 (i-1)*1024--totalNum
				List<AccountThirdXf> subList= xfList.subList((i-1)*1024,totalNum);
				int r =acountThirdXfMapper.batchInsert(subList);
				successCount =successCount +r;

			}
			else{
				//从(i-1)*1024--i*1024
				List<AccountThirdXf> subList= xfList.subList((i-1)*1024,1024*(i));
				int r=acountThirdXfMapper.batchInsert(subList);
				successCount =successCount+r;
			}
		}
		long end = System.currentTimeMillis();
		logger.info("导入先锋入金excel文件花费:"+(end - start)/1000+"s");
		if (totalNum==successCount){
			resultObj.setCode("1");
			resultObj.setMsg("先锋入金数据导入成功！");

		}
		else {
			resultObj.setCode("0");
			resultObj.setMsg("先锋入金数据导入失败！");
		}

		//持节化log
		try{
			DepositdataThirdImportlog depositdataThirdImportlog =new DepositdataThirdImportlog();
			depositdataThirdImportlog.setContrastDate(data);
			depositdataThirdImportlog.setCreatedTime(DateUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm"));
			depositdataThirdImportlog.setThirdPlatformType((short)1);
			depositdataThirdImportlog.setTotalNo(totalNum);
			depositdataThirdImportlog.setSuccessNo(successCount);
			int dr = depositdataThirdImportlogMapper.insertSelective(depositdataThirdImportlog);
			if (dr>0){
				logger.info("先锋入金数据持久化log成功存储!");
			}

		}catch (Exception e){
			e.printStackTrace();
		}
		return resultObj;
	}
}
